The QDA package format is used by buster in all his latest Windows games, like Guardian of Paradise and Akuji the Demon.
Like Fastfile, it condenses a directory full of images down to one package to be used as a mini-filesystem by the game.
The format begins with a 0×100 byte header, then begins a pattern where it repeats 268 byte chunks. Its maximum storable filename is 255 bytes. All values are stored in little endian ordering:
Null [4 bytes, long]
ID Tag: 'QDA0' [4 bytes, string]
File count [4 bytes, long]
(pad up to 0x100)
(file loop)
File offset [4 bytes, long]
File size [4 bytes, long]
Repeat file size [4 bytes, long (unconfirmed)
File name [256 bytes, string]
(end loop)
Despite not being certain about the repeated file size, I was able to successfully rebuild QDA packages from scratch and have them work in buster’s game by copying the file size to both offsets.
A proof of concept extractor is shown below:
$fd = fopen('bmp.qda', 'rb');
fseek($fd, 0x4, SEEK_SET);
if(fread($fd, 4)!="QDA0") die;
list($junk, $count) = unpack('l*', fread($fd, 4));
$offset = array();
$filesize = array();
$unknown = array();
$name = array();
for($i=0; $i< $count; $i++) {
list($junk, $offset[$i]) = unpack('l*', fread($fd, 4));
list($junk, $filesize[$i]) = unpack('l*', fread($fd, 4));
list($junk, $unknown[$i]) = unpack('l*', fread($fd, 4));
$filename[$i] = rtrim(fread($fd, 256));
}
for($i=0; $i<$count; $i++) {
$fo = fopen($filename[$i], 'w');
fseek($fd, $offset[$i], SEEK_SET);
fputs($fo, fread($fd, $filesize[$i]));
fclose($fo);
}
fclose($fd);